home *** CD-ROM | disk | FTP | other *** search
- unit FixupLB;
-
- // Simple unit that patches the StdCtrls.TCustomListBox.GetItemIndex
- // method in Delphi 4.0 (build 5.37)
- //
- // July 1998, by Hallvard Vassbotn (hallvard@falcon.no)
-
- interface
-
- implementation
-
- uses
- Windows,
- TypInfo,
- StdCtrls;
-
- type
- PPGetItemIndex = ^PGetItemIndex;
- PGetItemIndex = ^TGetItemIndex;
- TGetItemIndex = packed record
- PUSH_EBX : byte;
- MOV_EBX_EAX : word;
- CMP_BYTE_PTR : word;
- ADDR_Offset : Cardinal;
- False_ZERO : byte;
- JNZ : byte;
- ELSE_REL_ADDR : byte;
- PUSH_LParam : word;
- PUSH_WParam : word;
- PUSH_Msg : byte;
- Msg_Const : Cardinal;
- MOV_EAX_EBX : word;
- CALL : byte;
- end;
- PGetItemIndexInPackage = ^TGetItemIndexInPackage;
- TGetItemIndexInPackage = packed record
- JMP_DWORD: word;
- ActualGetItemIndex : PPGetItemIndex;
- end;
- TBytes = array[0..3] of byte;
-
- const
- OpCode_JNZ = $75;
- OpCode_JZ = $74;
- OpCode_JMP_DWORD = $25FF;
-
- function IsBuggyCode(var GetItemIndex: PGetItemIndex): boolean;
- var
- GetItemIndexInPackage: PGetItemIndexInPackage absolute GetItemIndex;
- begin
- // Verify that this is a static method
- Result := (TBytes(GetItemIndex)[3] < $FE);
- if Result then
- begin
- // Handle the case when TCustomList.GetItemIndex is in a package
- if (GetItemIndexInPackage^.JMP_DWORD = OpCode_JMP_DWORD) then
- GetItemIndex := GetItemIndexInPackage^.ActualGetItemIndex^;
-
- with GetItemIndex^ do
- begin
- Result :=
- // The buggy instruction, should have been OpCode_JZ
- (JNZ = OpCode_JNZ) and
- // Check the other instructions as well, just to be sure
- (PUSH_EBX = $53) and
- (MOV_EBX_EAX = $D88B) and
- (CMP_BYTE_PTR = $BB80) and
- (False_ZERO = $00) and
- (ELSE_REL_ADDR= $18) and
- (PUSH_LParam = $006A) and
- (PUSH_WParam = $006A) and
- (PUSH_Msg = $68) and
- (Msg_Const = $19f) and
- (MOV_EAX_EBX = $C38B) and
- (CALL = $E8) ;
- end;
- end;
- end;
-
- procedure WriteCodeByte(CodeAddress: pointer; Value: byte);
- var
- WrittenBytes: Cardinal;
- begin
- // Must use WriteProcessMemory or VirtualProtect to write to code segment
- WriteProcessMemory(GetCurrentProcess, CodeAddress, @Value, SizeOf(Value), WrittenBytes);
- end;
-
- type
- // Publish ItemIndex to easily get address of GetItemIndex method
- TPublishedListBox = class(TCustomListBox)
- published
- property ItemIndex;
- end;
-
- procedure Fix_TCustomListBox_GetItemIndex_Bug;
- var
- PropInfo : PPropInfo;
- GetItemIndex: PGetItemIndex;
- begin
- // Get the property information for the newly published ItemIndex property
- PropInfo := TypInfo.GetPropInfo(TPublishedListBox.ClassInfo, 'ItemIndex');
- if Assigned(PropInfo) then
- begin
- // Get the get-property method address
- GetItemIndex := PropInfo^.GetProc;
-
- // Now check that the buggy code is there
- if IsBuggyCode(GetItemIndex) then
- // Patch in the correction, voilα!
- // Same as GetItemIndex^.JNZ := OpCode_JZ, without the AV...
- WriteCodeByte(@GetItemIndex^.JNZ, OpCode_JZ);
- end;
- end;
-
- initialization
- Fix_TCustomListBox_GetItemIndex_Bug;
- end.
-